package coder.nav.utils;

import coder.nav.constants.NavRedisKeyConstants;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Date;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * jwt工具类
 * @author Bosen 2022/11/24 15:35
 **/
public class JwtUtils {

    public static final ThreadLocal<String> tokenThreadLocal = new ThreadLocal<>();
    public static RedisTemplate<String, String> redisTemplate;

    /**
     * 过期时间
     */
    public static final long EXPIRE_TIME = 30L * 24 * 60 * 60 * 1000;

    /**
     * 密钥
     */
    private static final String SECRET = "coder-nav";

    /**
     * 生成签名
     * @author Bosen 2022/11/24 15:36
     **/
    public static String sign(long userId) {
        try {
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            String token = JWT.create()
                    .withAudience(String.valueOf(userId))
                    .withExpiresAt(date)
                    .sign(algorithm);
            String key = getKey(userId, token);
            tokenThreadLocal.set(token);
            redisTemplate.delete(key);
            redisTemplate.opsForValue().set(key, token, JwtUtils.EXPIRE_TIME, TimeUnit.MILLISECONDS);
            return token;
        } catch (Exception ignored) {
            throw new RuntimeException("生成token失败");
        }
    }

    /**
     * 获取key
     * @author Bosen 2025/8/15 10:02
     */
    public static String getKey(long userId, String token) {
        return String.format(NavRedisKeyConstants.NAV_TOKEN_USER, userId, token);
    }

    /**
     * 直接获取缓存中的userId
     * @author Bosen 2025/2/28 21:55
     */
    public static Long getUserId() {
        String token = tokenThreadLocal.get();
        JwtUtils.checkToken(token);
        return JwtUtils.getUserIdByToken(token);
    }

    /**
     * 根据token获取userId
     * @author Bosen 2022/11/24 15:37
     **/
    public static Long getUserIdByToken(String token) {
        try {
            return Long.parseLong(JWT.decode(token).getAudience().get(0));
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 校验token
     * @author Bosen 2025/2/28 21:52
     */
    public static Boolean checkToken(String token) {
        Long userId = JwtUtils.getUserIdByToken(token);
        if(Objects.isNull(userId)) {
            return false;
        }
        String auth = redisTemplate.opsForValue().get(getKey(userId, token));
        if(StringUtils.isBlank(auth) || !auth.equals(token)) {
            return false;
        }
        tokenThreadLocal.set(auth);
        return Boolean.TRUE;
    }

    /**
     * 清空token
     * @author Bosen 2025/2/28 21:54
     */
    public static Boolean cleanToken(String token) {
        redisTemplate.delete(getKey(getUserId(), token));
        tokenThreadLocal.remove();
        return Boolean.TRUE;
    }
    
}
